#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm> //para la funcion sort()
#include <ctime> //para inicializar el generador de numeros aleatorios.
#include <string>

#include "Cliente.h"
#include "Caja.h"

#include "Super.h"
        
Super :: Super( const char * archivoIN ){
    
    ifstream archivo( archivoIN );
    
    archivo >> this->duracion;
    archivo >> this->cantCajas;
    archivo >> this->cantMaxClientes;
    archivo >> this->tiempoMaxAtencion;
    
    this->tiempoDeOcioTotal = 0;
    this->tiempoDeEsperaPromedioTotal = 0 ;
    
    //Seteo el tiempo maximo de atencion para todas las cajas.
    Caja :: setTiempoMaximoDeAtencion( tiempoMaxAtencion );
    
    //Inicio la semilla para el generador de numeros aleatorios
    srand(unsigned(time(NULL)));

}      
  
Super :: Super( int duracion, 
                int cantCajas,
                int cantMaxClientes, 
                int tiempoMaxAtencion ){

    this->duracion = duracion;
    this->cantCajas = cantCajas;
    this->cantMaxClientes = cantMaxClientes;
    this->tiempoMaxAtencion = tiempoMaxAtencion;
    
    this->tiempoDeOcioTotal = 0;
    this->tiempoDeEsperaPromedioTotal = 0 ;
    
    //Seteo el tiempo m�ximo de atencion para todas las cajas.
    Caja :: setTiempoMaximoDeAtencion( tiempoMaxAtencion );
    
    //Inicio la semilla para el generador de numeros aleatorios
    srand(unsigned(time(NULL)));

}

Super :: ~Super(){
}

void Super :: correrSimulacion(){
    
    int cantClientes = 0;
    
    bool verbose = false,
         debug = false;

    
    Caja C;
    
    //Lleno el vector con objetos Caja.
    for( int i = 0 ; i < cantCajas ; i++ ){
        cajas.push_back( C );
    }

    for( int ciclo = 1 ; ciclo <= duracion ; ciclo++){
        //Tomo un numero aleatorio de clientes, entre 0 y cantMaxClientes.
        cantClientes = rand() % cantMaxClientes;
        
        //Seteo en el mismo ciclo a TODOS los objetos caja.
        Caja :: setCiclo(ciclo);
        
        //Itero sobre el vector de objetos Caja y les aviso que estamos en un nuevo ciclo
        for( vector<Caja> :: iterator it = cajas.begin() ; it != cajas.end() ; it++ )
            it->nuevoCiclo();
        
        //Ordeno las cajas de acuerdo a la cantidad de clientes en cada cola; sort() usa QuickSort (O(N*log N))
        sort( cajas.begin() , cajas.end() );
        
        int cajaPivot = 0;
        
        /*Creo un objeto Cliente y lo encolo de forma pareja, desde la caja que menos
        clientes tiene en la cola. Le asigno al objeto cliente su ciclo de entrada.*/
        Cliente cli(ciclo);
        
        if( debug )
            cout << "\nEntran " << cantClientes << " clientes.\n\n";
        
        //Este es el ordenamiento de clientes en forma pareja en las cajas.
        while( cantClientes > 0 ){
                        
            while( cajaPivot < cantCajas - 1 && 
                   cajas[ cajaPivot ].getCantCli() == cajas[ cajaPivot + 1 ].getCantCli() )
                cajaPivot++;
                                                
            for( int k = cajaPivot ; k >= 0 && cantClientes > 0 ; k-- ){
                cajas[ k ].encolarCliente(cli);
                cantClientes--;
            }
      
        }
        
        if( debug ){
            cout << "---------------- SALIDA ----------------\n";
            for( int k = 0 ; k < cantCajas ; k++ )
                cout << cajas[ k ].getCantCli() << "\n";
            cout << "Para terminar ingrese \'x\' -> ";
            if( getchar() == 'x' )break;
        }
        
    
    }
    
    
    if(verbose)
        cout << "--------------Tiempos Parciales--------------\n";
    
    for( int j = 1 ; j <= cantCajas ; j++ ){
        tiempoDeOcioTotal += cajas[j - 1].getTiempoDeOcioTotal();             
        tiempoDeEsperaPromedioTotal += cajas[j - 1].getTiempoDeEsperaPromedio();
        
        if( verbose ){
            
            cout << "[Caja " << j << "] Tiempo Total de Ocio -> " 
                    << (cajas[j - 1].getTiempoDeOcioTotal()) << "\n";
            
            cout << "[Caja " << j << "] Tiempo Promedio de Espera -> " 
                    << (cajas[j - 1].getTiempoDeEsperaPromedio()) << "\n\n";
        }
        
    }
    
    if(verbose)
        cout << "--------------Tiempos Totales--------------\n";
           
}

float Super :: getTiempoDeOcioTotal() const{
    return tiempoDeOcioTotal / cantCajas;
}

float Super :: getTiempoDeEsperaPromedioTotal() const{
    return tiempoDeEsperaPromedioTotal / cantCajas;
}

